package org.studiox.graph.janusgraph.common;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.studiox.graph.common.GraphConfig;
import org.studiox.graph.common.IGraphWrapper;
import org.studiox.graph.common.exception.GraphException;

import java.util.Iterator;
import java.util.concurrent.ExecutionException;

import static org.studiox.graph.common.GraphConstant.JanusGraphConfigConstant.*;
import static org.studiox.graph.common.GraphConstant.JanusGraphInstanceConstant.GRAPH_UNIQUE_INSTANCE_ID;
import static org.studiox.graph.common.GraphConstant.JanusGraphInstanceConstant.GRAPH_UNIQUE_INSTANCE_PREFIX;
import static org.studiox.graph.common.GraphConstant.JanusGraphLabelPropertyKeyIndexConstant.*;
import static org.studiox.graph.common.GraphConstant.Separator.DOT;
import static org.studiox.graph.common.exception.GraphExceptionCode.JANUS_GRAPH_EXCEPTION;

/**
 * 遍历操作
 *
 * <p>out()、in()、both()、outE()、inE()、bothE()、outV()、inV()、bothV()、otherV()
 *
 * <p>遍历（以定点为基础）
 *
 * <p>1.out(label)：根据指定的 Edge Label 来访问顶点的 OUT 方向邻接点（可以是零个 Edge Label，代表所有类型边
 *
 * <p>也可以一个或多个 Edge Label，代表任意给定 Edge Label 的边，下同）
 *
 * <p>2.in(label)：根据指定的 Edge Label 来访问顶点的 IN 方向邻接点
 *
 * <p>3.both(label)：根据指定的 Edge Label 来访问顶点的双向邻接点
 *
 * <p>4.outE(label)： 根据指定的 Edge Label 来访问顶点的 OUT 方向邻接边
 *
 * <p>5.inE(label)：根据指定的 Edge Label 来访问顶点的 IN 方向邻接边
 *
 * <p>6.bothE(label)：根据指定的 Edge Label 来访问顶点的双向邻接边
 *
 * <p>遍历（以边为基础）
 *
 * <p>1.outV()：访问边的出顶点，出顶点是指边的起始顶点
 *
 * <p>2.inV()：访问边的入顶点，入顶点是指边的目标顶点，也就是箭头指向的顶点
 *
 * <p>3.bothV()：访问边的双向顶点
 *
 * <p>4.otherV()：访问边的伙伴顶点，即相对于基准顶点而言的另一端的顶点
 *
 * <p>查询路径path
 *
 * <p>path()、simplePath()、cyclicPath() 路径：就是经过的顶点成为路径
 *
 * <p>Path说明
 *
 * <p>在使用Gremlin对图进行分析时，关注点有时并不仅仅在最终到达的顶点、边或者属性上，通过什么样的路径到达最终的顶点、边和属性同样重要
 *
 * <p>此时可以借助path()来获取经过的路径信息。
 *
 * <p>path()返回当前遍历过的所有路径。有时需要对路径进行过滤，只选择没有环路的路径或者选择包含环路的路径
 *
 * <p>Gremlin针对这种需求提供了两种过滤路径的step：simplePath()和cyclicPath()
 *
 * <p>path()返回所有路径，包含有环路径和无环路径 simplePath()，过滤掉路径中含有环路的对象，只保留路径中不含有环路的对象
 *
 * <p>cyclicPath()，过滤掉路径中不含有环路的对象，只保留路径中含有环路的对象
 *
 * <p>循环操作
 *
 * <p>repeat()、times()、until()、emit()、loops()
 *
 * <p>repeat+times 根据次数来重复执行语句
 *
 * <p>repeat() + until() 根据条件来重复执行语句
 *
 * <p>repeat() + emit() 收集执行过程中的数据
 *
 * <p>repeat() + loops() 根据最大次数限制来重复执行语句
 */
public abstract class AbstractJanusGraph implements IGraphWrapper {

  private static final String VERTEX_UNIQ_ONLY_INDEX = "VERTEX_UNIQ_ONLY_INDEX";

  private static final String VERTEX_UNIQ_INDEX = "VERTEX_UNIQ_INDEX";

  private static final String VERTEX_TYPE_INDEX = "VERTEX_TYPE_INDEX";

  private static final String VERTEX_DELETED_INDEX = "VERTEX_DELETED_INDEX";

  private static final String VERTEX_CREATE_TIME_INDEX = "VERTEX_CREATE_TIME_INDEX";

  private static final String EDGE_UNIQ_INDEX = "EDGE_UNIQ_INDEX";

  private static final String EDGE_TYPE_INDEX = "EDGE_TYPE_INDEX";

  private static final String EDGE_DELETED_INDEX = "EDGE_DELETED_INDEX";

  private static final String EDGE_SOURCE_UNIQ_INDEX = "EDGE_SOURCE_UNIQ_INDEX";

  private static final String EDGE_TARGET_UNIQ_INDEX = "EDGE_TARGET_UNIQ_INDEX";

  private static final String EDGE_CREATE_TIME_INDEX = "EDGE_CREATE_TIME_INDEX";

  private static final String EDGE_SOURCE_TARGET_UNIQ_INDEX = "EDGE_SOURCE_TARGET_UNIQ_INDEX";

  private static final String EDGE_TYPE_SOURCE_UNIQ_INDEX = "EDGE_TYPE_SOURCE_UNIQ_INDEX";

  private static final String EDGE_TYPE_TARGET_UNIQ_INDEX = "EDGE_TYPE_TARGET_UNIQ_INDEX";

  private static final String EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX =
      "EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX";

  public abstract void setBuilderConfig(String key, Object value);

  public void buildGraphConfig() throws GraphException {
    Configuration graphConfig = GraphConfig.getGraphConfig();
    Iterator<String> iterator = graphConfig.getKeys();
    while (iterator.hasNext()) {
      String key = iterator.next();
      setBuilderConfig(key, graphConfig.getProperty(key));
    }
  }

  public void buildGraphConfig(Configuration config, String hbaseTableName) {
    if (!config.containsKey(STORAGE_BACKEND)
        || config.getString(STORAGE_BACKEND).equalsIgnoreCase(BACKEND_MEMORY)) {
      setBuilderConfig(STORAGE_BACKEND, BACKEND_MEMORY);
      setBuilderConfig(GREMLIN_GRAPH, JANUSGRAPH_FACTORY);
      return;
    }
    Iterator<String> iterator = config.getKeys();
    while (iterator.hasNext()) {
      String key = iterator.next();
      if (key.substring(0, key.indexOf(DOT)).equalsIgnoreCase(INDEX_PREFIX)) {
        continue;
      }
      setBuilderConfig(key, config.getProperty(key));
    }
    if (StringUtils.isNotBlank(hbaseTableName)) {
      setBuilderConfig(STORAGE_HBASE_TABLE, hbaseTableName);
    }
    setBuilderConfig(
        GRAPH_UNIQUE_INSTANCE_ID, GRAPH_UNIQUE_INSTANCE_PREFIX + System.currentTimeMillis());
  }

  public abstract boolean mgmtNotContainsVertexLabel(String vertexLabelName);

  public abstract void mgmtMakeVertexLabel(String vertexLabelName);

  public abstract boolean mgmtNotContainsEdgeLabel(String edgeLabelName);

  public abstract void mgmtMakeEdgeLabel(String edgeLabelName);

  private void buildGraphLabel() {
    if (mgmtNotContainsVertexLabel(LABEL_VERTEX)) {
      mgmtMakeVertexLabel(LABEL_VERTEX);
    }
    if (mgmtNotContainsEdgeLabel(LABEL_EDGE)) {
      mgmtMakeEdgeLabel(LABEL_EDGE);
    }
  }

  public abstract boolean mgmtNotContainsPropertyKey(String propertyKeyName);

  public abstract void mgmtMakePropertyKey(String propertyKeyName, Class<?> zlass);

  private void buildGraphPropertyKey() {
    if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_UNIQ)) {
      mgmtMakePropertyKey(VERTEX_PROPERTY_UNIQ, String.class);
    }
    if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_TYPE)) {
      mgmtMakePropertyKey(VERTEX_PROPERTY_TYPE, String.class);
    }
    if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_DELETED)) {
      mgmtMakePropertyKey(VERTEX_PROPERTY_DELETED, Boolean.class);
    }
    if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_CREATE_TIME)) {
      mgmtMakePropertyKey(VERTEX_PROPERTY_CREATE_TIME, Long.class);
    }

    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_UNIQ)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_UNIQ, String.class);
    }
    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_TYPE)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_TYPE, String.class);
    }
    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_DELETED)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_DELETED, Boolean.class);
    }
    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, String.class);
    }
    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_TARGET_VERTEX_UNIQ)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, String.class);
    }
    if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_CREATE_TIME)) {
      mgmtMakePropertyKey(EDGE_PROPERTY_CREATE_TIME, Long.class);
    }
  }

  public abstract boolean mgmtNotContainsGraphIndex(String indexName);

  public abstract void mgmtBuildVertexIndexOnlyWithOneKeyUnique(
      String indexName, String propertyKeyName, String labelName);

  public abstract void mgmtBuildVertexIndexWithOneKey(String indexName, String propertyKeyName);

  public abstract void mgmtBuildEdgeIndexWithOneKey(String indexName, String propertyKeyName);

  public abstract void mgmtBuildEdgeIndexWithTwoKey(
      String indexName, String firstPropertyKeyName, String secondPropertyKeyName);

  public abstract void mgmtBuildEdgeIndexWithThreeKey(
      String indexName,
      String firstPropertyKeyName,
      String secondPropertyKeyName,
      String thirdPropertyKeyName);

  public abstract boolean mgmtNotContainsRelationIndex(
      String edgeLabelName, String relationIndexName);

  public abstract void mgmtBuildRelationIndexWithOneKey(
      String edgeLabelName, String relationIndexName, String propertyKeyName);

  public abstract void mgmtBuildRelationIndexWithTwoKey(
      String edgeLabelName,
      String relationIndexName,
      String firstPropertyKeyName,
      String secondPropertyKeyName);

  public abstract void mgmtBuildRelationIndexWithThreeKey(
      String edgeLabelName,
      String relationIndexName,
      String firstPropertyKeyName,
      String secondPropertyKeyName,
      String thirdPropertyKeyName);

  private void buildGraphVertexIndex() {
    if (mgmtNotContainsGraphIndex(VERTEX_UNIQ_ONLY_INDEX)) {
      mgmtBuildVertexIndexOnlyWithOneKeyUnique(
          VERTEX_UNIQ_ONLY_INDEX, VERTEX_PROPERTY_UNIQ, LABEL_VERTEX);
    }
    if (mgmtNotContainsGraphIndex(VERTEX_UNIQ_INDEX)) {
      mgmtBuildVertexIndexWithOneKey(VERTEX_UNIQ_INDEX, VERTEX_PROPERTY_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(VERTEX_TYPE_INDEX)) {
      mgmtBuildVertexIndexWithOneKey(VERTEX_TYPE_INDEX, VERTEX_PROPERTY_TYPE);
    }
    if (mgmtNotContainsGraphIndex(VERTEX_DELETED_INDEX)) {
      mgmtBuildVertexIndexWithOneKey(VERTEX_DELETED_INDEX, VERTEX_PROPERTY_DELETED);
    }
    if (mgmtNotContainsGraphIndex(VERTEX_CREATE_TIME_INDEX)) {
      mgmtBuildVertexIndexWithOneKey(VERTEX_CREATE_TIME_INDEX, VERTEX_PROPERTY_CREATE_TIME);
    }
  }

  private void buildGraphEdgeIndex() {
    if (mgmtNotContainsGraphIndex(EDGE_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_UNIQ_INDEX, EDGE_PROPERTY_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(EDGE_TYPE_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_TYPE_INDEX, EDGE_PROPERTY_TYPE);
    }
    if (mgmtNotContainsGraphIndex(EDGE_DELETED_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_DELETED_INDEX, EDGE_PROPERTY_DELETED);
    }
    if (mgmtNotContainsGraphIndex(EDGE_SOURCE_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(EDGE_TARGET_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(EDGE_CREATE_TIME_INDEX)) {
      mgmtBuildEdgeIndexWithOneKey(EDGE_CREATE_TIME_INDEX, EDGE_PROPERTY_CREATE_TIME);
    }

    if (mgmtNotContainsGraphIndex(EDGE_SOURCE_TARGET_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithTwoKey(
          EDGE_SOURCE_TARGET_UNIQ_INDEX,
          EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
          EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(EDGE_TYPE_SOURCE_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithTwoKey(
          EDGE_TYPE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_TYPE, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
    }
    if (mgmtNotContainsGraphIndex(EDGE_TYPE_TARGET_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithTwoKey(
          EDGE_TYPE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TYPE, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }

    if (mgmtNotContainsGraphIndex(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX)) {
      mgmtBuildEdgeIndexWithThreeKey(
          EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX,
          EDGE_PROPERTY_TYPE,
          EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
          EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
  }

  private void buildGraphRelationIndex() {
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_UNIQ_INDEX, EDGE_PROPERTY_UNIQ);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_TYPE_INDEX, EDGE_PROPERTY_TYPE);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_DELETED_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_DELETED_INDEX, EDGE_PROPERTY_DELETED);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(
          LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(
          LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_CREATE_TIME_INDEX)) {
      mgmtBuildRelationIndexWithOneKey(
          LABEL_EDGE, EDGE_CREATE_TIME_INDEX, EDGE_PROPERTY_CREATE_TIME);
    }

    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithTwoKey(
          LABEL_EDGE,
          EDGE_SOURCE_TARGET_UNIQ_INDEX,
          EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
          EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithTwoKey(
          LABEL_EDGE,
          EDGE_TYPE_SOURCE_UNIQ_INDEX,
          EDGE_PROPERTY_TYPE,
          EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
    }
    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithTwoKey(
          LABEL_EDGE,
          EDGE_TYPE_TARGET_UNIQ_INDEX,
          EDGE_PROPERTY_TYPE,
          EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }

    if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX)) {
      mgmtBuildRelationIndexWithThreeKey(
          LABEL_EDGE,
          EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX,
          EDGE_PROPERTY_TYPE,
          EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
          EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
    }
  }

  public abstract void mgmtCommit();

  public abstract void mgmtRollback();

  public abstract void updateGraphIndexWithReindex(String indexName)
      throws ExecutionException, InterruptedException;

  public abstract void updateRelationIndexWithReindex(
      String edgeLabelName, String relationIndexName)
      throws ExecutionException, InterruptedException;

  private void updateGraphIndex() throws ExecutionException, InterruptedException {
    try {
      updateGraphIndexWithReindex(VERTEX_UNIQ_ONLY_INDEX);
      updateGraphIndexWithReindex(VERTEX_UNIQ_INDEX);
      updateGraphIndexWithReindex(VERTEX_TYPE_INDEX);
      updateGraphIndexWithReindex(VERTEX_DELETED_INDEX);
      updateGraphIndexWithReindex(VERTEX_CREATE_TIME_INDEX);

      updateGraphIndexWithReindex(EDGE_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_TYPE_INDEX);
      updateGraphIndexWithReindex(EDGE_DELETED_INDEX);
      updateGraphIndexWithReindex(EDGE_SOURCE_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_TARGET_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_CREATE_TIME_INDEX);
      updateGraphIndexWithReindex(EDGE_SOURCE_TARGET_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_TYPE_SOURCE_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_TYPE_TARGET_UNIQ_INDEX);
      updateGraphIndexWithReindex(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);

      mgmtCommit();
    } catch (ExecutionException | InterruptedException e) {
      mgmtRollback();
      throw e;
    }
  }

  private void updateGraphRelationIndex() throws ExecutionException, InterruptedException {
    try {
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_DELETED_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_CREATE_TIME_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX);
      updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);

      mgmtCommit();
    } catch (ExecutionException | InterruptedException e) {
      mgmtRollback();
      throw e;
    }
  }

  public abstract void awaitGraphIndexStatusWithEnabled(String indexName)
      throws InterruptedException;

  public abstract void awaitRelationIndexStatusWithEnabled(
      String edgeLabelName, String relationIndexName) throws InterruptedException;

  private void awaitGraphIndexStatus() throws InterruptedException {
    awaitGraphIndexStatusWithEnabled(VERTEX_UNIQ_ONLY_INDEX);
    awaitGraphIndexStatusWithEnabled(VERTEX_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(VERTEX_TYPE_INDEX);
    awaitGraphIndexStatusWithEnabled(VERTEX_DELETED_INDEX);
    awaitGraphIndexStatusWithEnabled(VERTEX_CREATE_TIME_INDEX);

    awaitGraphIndexStatusWithEnabled(EDGE_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_TYPE_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_DELETED_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_SOURCE_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_TARGET_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_CREATE_TIME_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_SOURCE_TARGET_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_TYPE_SOURCE_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_TYPE_TARGET_UNIQ_INDEX);
    awaitGraphIndexStatusWithEnabled(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
  }

  private void awaitGraphRelationIndexStatus() throws InterruptedException {
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_DELETED_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_CREATE_TIME_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX);
    awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
  }

  @Override
  public void open() throws GraphException {
    try {
      buildGraphLabel();
      buildGraphPropertyKey();
      buildGraphVertexIndex();
      buildGraphEdgeIndex();
      buildGraphRelationIndex();
      mgmtCommit();
      // updateGraphIndex();
      // updateGraphRelationIndex();
      // awaitGraphIndexStatus();
      // awaitGraphRelationIndexStatus();
    } catch (Throwable t) {
      throw new GraphException(t, JANUS_GRAPH_EXCEPTION);
    }
  }

  public abstract Long getJanusGraphVertexId(String uniq);
}
